import frappe
from frappe import _
from frappe.utils import flt
from erpnext.manufacturing.doctype.job_card.job_card import JobCard
from frappe.model.mapper import get_mapped_doc
from frappe.model.naming import get_default_naming_series

class CustomJobCard(JobCard):
    @property
    def custom_sent_qty(self):
        """获取委外发出数量"""
        if not self.operation_id:
            return 0
            
        sent_qty = frappe.db.get_value(
            "Work Order Operation",
            self.operation_id,
            "custom_sent_qty"
        ) or 0
        return sent_qty
    
    @property
    def custom_received_qty(self):
        """获取委外入库数量"""
        if not self.operation_id:
            return 0
            
        received_qty = frappe.db.get_value(
            "Work Order Operation",
            self.operation_id,
            "custom_received_qty"
        ) or 0
        return received_qty
    
    @property
    def custom_scrapped_qty(self):
        """获取委外废品数量"""
        if not self.operation_id:
            return 0
            
        scrapped_qty = frappe.db.get_value(
            "Work Order Operation",
            self.operation_id,
            "custom_scrapped_qty"
        ) or 0
        return scrapped_qty
    
    @property
    def custom_wip_qty(self):
        """获取在制品入库数量"""
        # 从已提交且加工单号为当前加工单的在制品移转单中获取在制品入库数量，是用 db.sql 查询
        wip_qty = frappe.db.sql("""
            SELECT SUM(qty) FROM `tabWip Transfer Item`
            WHERE job_card = %s
            AND parent IN (
                SELECT name FROM `tabWip Transfer`
                WHERE docstatus = 1 AND type = 'Receive from Workshop'
            )
        """, (self.name,), as_dict=1)
        return wip_qty[0].qty if wip_qty else 0
        
            


@frappe.whitelist()
def make_wip_transfer(source_name, target_doc=None):
    """创建从加工单到在制品移转单的映射"""
    
    # 从 frappe.flags.args 中获取 transfer_type
    transfer_type = None
    if hasattr(frappe.flags, 'args') and frappe.flags.args:
        transfer_type = frappe.flags.args.get('transfer_type')
    
    # 根据不同的转移类型设置不同的验证条件
    validation = {}
    if transfer_type == "Receive from Workshop":
        # 在制品入库需要已提交的加工单
        validation = {"docstatus": ["=", 1]}
    elif transfer_type == "Send to Supplier" or transfer_type == "Receive from Supplier":
        # 委外发料和委外入库只需要草稿状态
        validation = {"docstatus": ["=", 0]}
    
    # 定义设置缺失值的函数
    def set_missing_values(source, target):
        # 设置单据编号模板
        target.naming_series = get_default_naming_series("Wip Transfer")
        # 设置移转类型
        target.type = transfer_type
    
    doclist = get_mapped_doc(
        "Job Card", 
        source_name, 
        {
            "Job Card": {
                "doctype": "Wip Transfer",
                "field_map": {
                    "custom_plant_floor": "plant_floor",
                    "custom_supplier": "from_supplier",
                },
                "validation": validation
            }
        }, 
        target_doc,
        set_missing_values  # 使用回调函数设置缺失值
    )
    
    # 添加一个移转项
    wip_item = frappe.new_doc("Wip Transfer Item")
    wip_item.job_card = source_name
    wip_item.work_order = frappe.db.get_value("Job Card", source_name, "work_order")
    wip_item.operation = frappe.db.get_value("Job Card", source_name, "operation")
    
    # 获取加工单信息
    job_card = frappe.get_doc("Job Card", source_name)
    work_order = frappe.get_doc("Work Order", job_card.work_order)
    
    # 根据移转类型设置不同的数量和仓库
    if transfer_type == "Receive from Workshop":
        # 车间入库 - 使用加工单的完工数量和报废数量
        wip_item.qty = job_card.total_completed_qty
        wip_item.scrap_qty = job_card.process_loss_qty
        wip_item.total_qty = job_card.total_completed_qty + job_card.process_loss_qty
    
    elif transfer_type == "Send to Supplier":
        # 委外发料 - 使用上一道工序的完工数量
        
        # 获取当前工序在工单中的位置
        current_operation_idx = 1
        
        for op in work_order.operations:
            if op.operation == job_card.operation:
                current_operation_idx = op.idx
                break
        
        # 如果不是第一道工序，获取上一道工序的完工数量
        if current_operation_idx > 1:
            prev_operation = work_order.operations[current_operation_idx - 2]
            
            # 直接从工序明细中获取在制品入库数量
            prev_completed_qty = prev_operation.custom_wip_qty or 0
            
            if prev_completed_qty > 0:
                wip_item.qty = prev_completed_qty
                wip_item.total_qty = prev_completed_qty
            else:
                # 如果上一道工序没有完工数量，报错提示
                frappe.throw(_("The previous operation has not completed, please complete the previous operation first."))
        else:
            # 如果是第一道工序，提示第一道工序不能进行委外发料
            frappe.throw(_("The first operation cannot be sent to a supplier."))
    
    elif transfer_type == "Receive from Supplier":
        # 委外入库 - 使用之前委外发料单的数量
        
        # 使用正确的方式查询子表
        # 方法1：使用SQL直接查询
        issue_transfers = frappe.db.sql("""
            SELECT parent FROM `tabWip Transfer Item`
            WHERE job_card = %s
            AND parent IN (
                SELECT name FROM `tabWip Transfer`
                WHERE docstatus = 1 AND type = 'Send to Supplier'
            )
        """, (source_name,), as_dict=1)
        
        if issue_transfers:
            # 获取最新的委外发料单
            latest_transfer = frappe.get_doc("Wip Transfer", issue_transfers[0].parent)
            
            # 查找对应的明细行
            for item in latest_transfer.wip_transfer_item:
                if item.job_card == source_name:
                    # 考虑退货数量
                    wip_item.qty = item.qty - item.returned_qty
                    break
            else:
                # 如果没有找到对应的明细行，报错提示
                frappe.throw(_("No issue transfer found for the job card."))
        else:
            # 如果没有找到委外发料单，报错提示
            frappe.throw(_("No issue transfer found for the job card."))
        
        # 设置入库数量等于数量（没有废品）
        wip_item.total_qty = wip_item.qty
    
    doclist.append("wip_transfer_item", wip_item)
    
    return doclist

def get_default_naming_series(doctype):
    """获取文档类型的默认命名系列，考虑用户自定义设置"""
    # 首先检查是否有用户自定义的默认值
    property_setter = frappe.db.get_value(
        "Property Setter",
        {
            "doc_type": doctype,
            "field_name": "naming_series",
            "property": "default"
        },
        "value"
    )
    
    if property_setter:
        return property_setter

    return frappe.model.naming.get_default_naming_series(doctype)